package com.xrj.gateway.interceter;

import com.alibaba.fastjson.JSON;
import com.mall.common.annotation.PassToken;
import com.mall.common.exception.AuthFailException;
import com.mall.user.dto.entity.TbMember;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.http.HttpMethod;
import org.springframework.stereotype.Component;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;
import utils.CookieUtils;
import utils.JwtTokenUtils;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.lang.reflect.Method;

/**
 * 用来实现token拦截认证
 * <p>
 * 其实就是用来判断当前这个操作是否需要登录
 */
@Slf4j
@Component
public class TokenInterceptor extends HandlerInterceptorAdapter{


    public static String ACCESS_TOKEN = "access_token";

    public static String USER_INFO_KEY = "userInfo";

    private final ThreadLocal<Long> startTimeThreadLocal = new ThreadLocal<>();

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception{
        // 开始时间（该数据只有当前请求的线程可见）
        startTimeThreadLocal.set(System.currentTimeMillis());
        if (HttpMethod.OPTIONS.matches(request.getMethod())) {
            return true;
        }
        HandlerMethod handlerMethod = (HandlerMethod) handler;
        boolean pass = isPassToken(handlerMethod);
        if (pass) {
            return true;
        }
        String token = CookieUtils.getCookieValue(request, ACCESS_TOKEN);
        log.info("拦截器拦截请求url: {}, 请求方法：{}, token: {}",
                request.getRequestURL().toString(), request.getMethod(), token);
        if (StringUtils.isBlank(token)) {
            throw new AuthFailException("token cannot be empty!");
        }

        String json = JwtTokenUtils.freeJwt(token);
        TbMember user = JSON.parseObject(json, TbMember.class);
        //每次请求会解析token设置用户信息
        request.setAttribute(USER_INFO_KEY, user);
        return true;
    }

    private boolean isPassToken(HandlerMethod handlerMethod) {
        Class<?> beanType = handlerMethod.getBeanType();
        if (beanType.isAnnotationPresent(PassToken.class)) {
            return true;
        }
        Method method = handlerMethod.getMethod();
        return method.isAnnotationPresent(PassToken.class);
    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        final Long startTime = startTimeThreadLocal.get();
        final Long endTime = System.currentTimeMillis();
        startTimeThreadLocal.remove();
        String path = request.getServletPath();
        log.info("拦截器响应url:{}, 耗时：{}", path, endTime-startTime);
        super.afterCompletion(request, response, handler, ex);
    }
}
